/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package traffic_lights;

import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

/**
 * Class that generates the intersection, controls car movement, and draws the intersection.
 * @author Luke Bermingham
 */
public class Intersection {

    private String h_Lanes = "1"; //trial numbers until imported from main
    private String v_Lanes = "1"; //trial numbers until imported from main
    private Float prob_VCar = 0.5f;
    private Float prob_HCar = 0.5f;
    private ArrayList<ArrayList> VertArray = new ArrayList();
    private ArrayList<ArrayList> HorzArray = new ArrayList();
    private String h_Lights = "Red"; //Flag for horizontal traffic lights
    private String v_Lights = "Red"; //Flag for vertical traffic lights
    private int lights_Counter = 0;


    /**
     * Method that generates all the lane data and defines the amount of times the simulation will run.
     * @param runs Value that that is passed to simulate method.
     * Determines the number of times that the simulation will be run.
     */
    public void initiate(String runs) {
        generate_LaneData(); //create vertical and horizontal arrayLists
        simulate(runs); //pass amount of run cycles to the simualtion method

    } //close simulation method

    /**
     * Method that calls: intersection drawing, car movement, and car generation.
     * Inside this method traffic light logic is also performed.
     * @param runs A value that determines how many times the simulation is run.
     */
    public void simulate(String runs) {
        int counter = 0;
        while (counter < Integer.parseInt(runs)) {

            draw_Intersection(); //outputs the intersection and arrayLists
            moveHCars();
            moveVCars();

            //////////Lights Cycle//////////

            if (lights_Counter == 10) {
                v_Lights = "Green";
            } else if (lights_Counter == 15) {
                v_Lights = "Red";
            } else if (lights_Counter == 19) {
                h_Lights = "Green";
            } else if (lights_Counter == 24) {
                h_Lights = "Red";
                lights_Counter = 6; //reset the counter
            }

            ArrayList tempVCars = generateVCars(); //generates all cars in the verticals lanes
            VertArray.set(0, tempVCars); //places generated cars into first element Red vertical

            ArrayList tempHCars = generateHCars(); //generates all cars in horizontal lanes
            if (tempHCars != null) {
                for (int i = 0; i < HorzArray.size(); i++) {
                    HorzArray.get(i).set(0, tempHCars.get(i)); //set cuurent nested array first element to current newCar
                }
            }
            counter++;
            lights_Counter++;
        }
        System.out.println("Would you like to continue simulating? Y/N?");
        Scanner input = new Scanner(System.in); //open a new scanner
        String run_again = input.nextLine(); //store the user input in a variable
        if (run_again.equals("Y") || run_again.equals("y")) {
            simulate("1"); //run the simulation for one more cycle
        }
    }

    /**
     * Setter method for the vertical lanes variable.
     * @param vertLanes Variable for number of vertical lanes.
     */
    public void setV_Lanes(String vertLanes) {
        v_Lanes = vertLanes; //sets Vertical lanes to whatever argument value vertLanes is given
    }

    /**
     * Setter method for the horizontal lanes variable.
     * @param Variable for number of horizontal lanes.
     */
    public void setH_Lanes(String horzLanes) {
        h_Lanes = horzLanes; //sets Horizontal lanes to whatever argument value horzLanes is given
    }

    /**
     * Setter method for the probability of a car entering the vertical lanes.
     * @param verticalProb Variable passed from menu for probability of a car generated in the vertical lane.
     */
    public void setVProb(Float verticalProb) {
        prob_VCar = verticalProb;
    }

    /**
     * Setter method for the probability of a car entering the Horizontal lanes.
     * @param horizontalProb Variable passed from menu for probability of a car generated in the horizontal lane.
     */
    public void setHProb(Float horizontalProb) {
        prob_HCar = horizontalProb;
    }

    /**
     * Generates cars for the vertical lanes of the intersection.
     * It is assumed a maximum of one car can be generated per cycle of the simulation.
     * The probability that a car is generated is determined by a user entered probability between 0 and 1.
     * @return An ArrayList with elements equal to vertical lanes, used in simulation.
     */
    public ArrayList generateVCars() {

        int overflow_Flag = 0; //counter for measuring fullness of vertical lanes
        ArrayList newHCars = new ArrayList();
        Random rnd = new Random(); //new instance of object random
        Float compareFloat = 0.0f; //instatiate a float

        for (int i = 0; i < Integer.parseInt(h_Lanes); i++) { //for each lane
            if (VertArray.get(1).get(i).equals("c")) { //if elem in that lane is C
                overflow_Flag++; //increase the counter
            }
        }

        for (int i = 0; i < Integer.parseInt(h_Lanes); i++) { // for each horizontal lane
            newHCars.add(" "); //a new car is made
        }
        compareFloat = rnd.nextFloat(); //generate random number
        if (compareFloat <= prob_HCar && overflow_Flag != Integer.parseInt(h_Lanes)) { //if the random number is less than or equal to the probability of a new car
            newHCars.set(rnd.nextInt(Integer.parseInt(h_Lanes)), "c");
        }
        overflow_Flag = 0; //reset the over flow flag
        return newHCars;
    }

    /**
     * Generates cars for the horizontal lanes of the intersection.
     * It is assumed a maximum of one car can be generated per cycle of the simulation.
     * The probability that a car is generated is determined by a user entered probability between 0 and 1.
     * @return An ArrayList with elements equal to horizontal lanes, used in simulation.
     */
    public ArrayList generateHCars() {

        int overflow_Flag = 0; //counter that declares the fullness of the intersection
        for (int i = 0; i < HorzArray.size(); i++) {
            if (HorzArray.get(i).get(1).equals("C")) { //if car is in elem 2 of intersection
                overflow_Flag++; //increase the flag
            }
        }

        ArrayList newHCars = new ArrayList();
        Random rnd = new Random(); //new instance of object random
        Float compareFloat = 0.0f;

        for (int i = 0; i < Integer.parseInt(v_Lanes); i++) { // for each horizontal lane
            newHCars.add(" "); //a new elem
        }

        compareFloat = rnd.nextFloat();
        if (compareFloat <= prob_VCar && overflow_Flag != Integer.parseInt(v_Lanes)) { //if the random number is less than or equal to the probability of a new car
            newHCars.set(rnd.nextInt(Integer.parseInt(v_Lanes)), "C"); //put a car in a random lane
        } else {
            newHCars = null;
        }
        overflow_Flag = 0; //reset counter
        return newHCars;
    }

    /**
     * Method used to generate the ArrayLists for horizontal and vertical lanes.
     */
    public void generate_LaneData() {

        for (int i = 0; i < 21; i++) {
            VertArray.add(generate_VLanes()); //add arraylist containing horizontal gap 21 times
        }

        for (int i = 0; i < Integer.parseInt(v_Lanes); i++) {
            HorzArray.add(generate_HLane()); //add arraylist containing one horizontals running lane a set num of times
        }
    }

    /**
     * Method used for vertical lane generation.
     * @return A blank ArrayList of elements [" ", " ", " " etc]. With length determined by number of vertical lanes.
     */
    public ArrayList generate_VLanes() {
        ArrayList tempList_V = new ArrayList();
        for (int i = 0; i < Integer.parseInt(h_Lanes); i++) {
            tempList_V.add(" "); //make blank lanes
        }
        return tempList_V;
    }

    /**
     * Method used for horizontal lane generation.
     * @return A blank ArrayList of elements [" ", " ", " " etc]. With length determined by number of horizontal lanes.
     */
    public ArrayList generate_HLane() {
        ArrayList tempList_H = new ArrayList();
        int spaces = 22 + Integer.parseInt(h_Lanes); //to get to number of spaces for horizontal lanes
        for (int i = 0; i < spaces; i++) { //for every space required make a new element in the array
            tempList_H.add(" ");
        }
        return tempList_H;
    }

    /**
     * Method used for drawing of the intersection.
     * This method is called by the simulation method based of number of cycles desired.
     * The method works by printing the vertical and horizontal arrays surrounded by corresponding edges.
     */
    public void draw_Intersection() {

        String blanks = "          "; //used for filling in intersection
        String dashes = "----------"; //used or surrounding the intersection
        String filler = blanks; //used for filling in the intersectiRed outline

        for (int i = 0; i < VertArray.size(); i++) { //for loop for printing surround and first half of vertical intersection.

            if (i == 9) { //when up to printing the 9th line
                filler = dashes; //print dashes instead of filler
            } else if (i == 10) {
                filler = blanks;
                break; //if i reches 10th index break the loop
            }

            System.out.print(filler + "|");
            for (int j = 0; j < VertArray.get(i).size(); j++) { //display the horizRedtal gap
                System.out.print(VertArray.get(i).get(j)); //prints current index of nested array
            }
            System.out.print("|" + filler);
            System.out.print("\n");
        }
        for (int i = 0; i < HorzArray.size(); i++) { //for loops in for loops used for outputing horzontal ArrayList
            for (int j = 0; j < HorzArray.get(i).size(); j++) {
                System.out.print(HorzArray.get(i).get(j));
            }
            System.out.print("\n");
        }

        for (int i = 0; i < VertArray.size(); i++) { //for loop that controls printing the surrounds and second half of the vertical intersection
            if (i == 0) {
                filler = dashes;
            } else if (i == 10) {
                filler = blanks;
                break; //if i reches 10th index break the loop
            } else {
                filler = blanks;
            }
            ArrayList temp = (ArrayList) VertArray.get(i + 10); //make an alias for nested referencing and increase index by 10
            System.out.print(filler + "|");
            for (int j = 0; j < temp.size(); j++) { //display the horizontal gap
                System.out.print(temp.get(j)); //prints current index of nested array
            }
            System.out.print("|" + filler);
            System.out.print("\n");
        }
        System.out.println("Vertical Lights = " + v_Lights);
        System.out.println("Horizontal Lights = " + h_Lights);
        System.out.println("\n");
    }

    /**
     * This method controls all the logic for moving the cars in the vertical lanes.
     * The cars stop when the traffic lights are red and overtake when a lane is blocked.
     * Due to the structure of the program the vertical cars also transfer to the horizontal ArrayList to cross the intersection.
     */
    public void moveVCars() {
        for (int i = VertArray.size() - 1; i > -1; i--) {
            for (int j = 0; j < VertArray.get(0).size(); j++) {
                if (VertArray.get(i).get(j).equals("c")) { //if elem equals C then
                    if (i == VertArray.size() - 1) {
                        VertArray.get(i).set(j, " "); //if the current arrayllist is last arraylist with Car set to " "
                    } else if (i == 9 && v_Lights.equals("Green")) {
                        HorzArray.get(0).set(11 + j, "c"); //move Car from Vertical to Horizontal
                        VertArray.get(i).set(j, " "); //remove Car from where ti sued to be
                    } else if (i == 9 && v_Lights.equals("Red")) { //if elem up to intersection an lights are Red then
                        //Do nothing
                    } else if (VertArray.get(i + 1).get(j).equals("c")) { //if the space being moved to is a car
                        for (int k = 0; k < VertArray.get(0).size(); k++) { //check other lanes from 0 - max
                            if (VertArray.get(i).get(k).equals(" ")) { //if the elem is blank
                                VertArray.get(i).set(k, "c"); //move a car there
                                VertArray.get(i).set(k, " "); //reset the car's original position to blank
                            }
                        }
                    } else {
                        VertArray.get(i + 1).set(j, "c"); //move Car to next array list
                        VertArray.get(i).set(j, " "); //set elem moved from to a " "
                    }
                }
                if (i == 10 && VertArray.get(10).get(j).equals("c")) {
                    VertArray.get(10).set(j, "c"); //transform little c into big C
                }
            }
        }
    }

    /**
     * This method controls all the logic for moving the cars in the horizontal lanes.
     * The cars stop when the traffic lights are red and overtake when a lane is blocked.
     * This method also controls the vertical cars that are crossing through the intersection and dependant on their
     * position deposits them back into the vertical ArrayList.
     */
    public void moveHCars() {
        for (int i = HorzArray.size() - 1; i > -1; i--) {
            for (int j = HorzArray.get(0).size() - 1; j > -1; j--) {
                if (HorzArray.get(i).get(j).equals("C")) { //if elem equals C then
                    if (j == HorzArray.get(0).size() - 1) {
                        HorzArray.get(i).set(j, " ");
                    } else if (h_Lights.equals("Red") && j == 10) {
                        //DO NOTHING
                    } else if (HorzArray.get(i).get(j + 1).equals("C")) { //if the space being moved to is a car
                        for (int k = 0; k < HorzArray.size(); k++) { //check other lanes from 0 - max
                            if (HorzArray.get(k).get(j + 1).equals(" ")) { //if the elem is blank
                                HorzArray.get(k).set(j + 1, "C"); //move a car there
                                HorzArray.get(i).set(j, " "); //reset the car's original position to blank
                            }
                        }
                    } else {
                        HorzArray.get(i).set(j + 1, "C"); //Make next elem equal to C
                        HorzArray.get(i).set(j, " "); //Make current elem equals to a " "
                    }
                } else if (HorzArray.get(i).get(j).equals("c")) { //if the elem equals a small c
                    if (i != HorzArray.size() - 1) { //and the elem is in the last lane
                        HorzArray.get(i + 1).set(j, "c"); //move the vertical car
                        HorzArray.get(i).set(j, " "); //reset the elem to " "
                    } else {
                        VertArray.get(10).set(j - 11, "c"); //move elem from HorzArray to VertArray
                        HorzArray.get(i).set(j, " ");
                    }

                }

            }
        }
    }
}
